package com.ftg.learn;

/**
 * 链式 实现线性存储结构
 * 链式
 * Node（单节点  data  pointer[前|后]）
 *
 * @author
 * @date 2024/2/29
 */
public class MyLinkedList<X> implements List<X> {

    /**
     * 内部类
     * 概念 ： 在一个类中定义一个类。在类的作用域  {}里面二次定义一个class,把里面的类叫做内部类，外面的类叫做外部类。
     * 意义：  更好的封装 ，保密性
     * 使用场景 ： 类 成员变量  成员方法  成员内部类(1:强调保密性  2：类里面做回调处理 lambda表达式)
     */
    private class Node {

        private final X data;
        private Node next;

        Node(X data, Node next) {
            this.data = data;
            this.next = next;
        }

        Node(X data) {
            this.data = data;
        }

        public Node getNext() {
            return next;
        }

        public void setNext(Node next) {
            this.next = next;
        }
    }

    /**
     * 单向链表的头
     */
    private Node head;

    /**
     * 单向链表的尾
     */
    private Node tail;

    private int size;

    /**
     * 速度较快
     * @param val 元素
     */
    @Override
    public void add(X val) {
        if(null == head){
            head = new Node(val);
            tail = head;
        }else{
            tail.setNext(new Node(val));
            tail = tail.getNext();
        }
        this.size++;
    }

    @Override
    public X get(int index) {
        return this.getNodeByIndex(index).data;
    }

    @Override
    public int size() {
        return this.size;
    }


    /**
     * 根据索引获取节点
     * @param index 索引
     * @return 节点
     */
    private Node getNodeByIndex(int index) {
        if(index < 0 ){
            throw new RuntimeException("下标不能小于0");
        }
        if(index > size-1){
            throw new RuntimeException("下标不能大于size");
        }
        if(index == 0){
            return head;
        }
        if (index == size-1){
            return tail;
        }
        // 计录现在查找到第几个元素了
        int i = 0;
        Node temp = head;
        while(temp.getNext() != null && i++ < index){
            temp = temp.getNext();
        }
        return temp;
    }


    @Override
    public void remove(int index) {
        //index = 0; 你想删除头节点
        if(index == 0){
            if(null != head){
                if(this.size >1){
                    head = head.getNext();
                }else{
                    head = null;
                    tail = null;
                }
            }else {
                throw new RuntimeException("链表里面没有元素不能删除");
            }
            this.size--;
            return;
        }

        Node preNode = this.getNodeByIndex(index - 1);
        if(index == this.size-1){
            preNode.setNext(null);
            tail = preNode;
        }else{
            preNode.setNext(preNode.getNext().getNext());
        }
        this.size--;
    }

    public static void main(String[] args) {
        //可变性比较强的  面向接口编程  面向父类编程
        List<Integer> list = new MyLinkedList<>();
        list.add(99);
        list.add(98);
        list.add(97);

        List<Integer> list1 = new MyArray<>();
        list1.add(1);
        list1.add(2);
        list1.add(3);

        //1 什么时候考虑用  Mylinked（头寻址到真正元素 慢 删除不要移位，所以较快）  什么时候考虑用MyArray(随机访问速度快，删除移位所以较慢)

        for(int i = 0 ;i < list.size();i++){
            System.out.println(list.get(i));
        }

        System.out.println(list);
    }
}
